#include "dht11.h"

static ssize_t dht11_read(struct file *file, char __user *buf, size_t len, loff_t *pos);

static int dht11_probe(struct platform_device *pdev);
static int dht11_remove(struct platform_device *pdev);

//设备号
static dev_t dht11_num;
//cdev对象
static struct cdev dht11_cdev;
//class对象
static struct class *dht11_class;
//操作函数
static struct file_operations dht11_ops = {
	.owner = THIS_MODULE,
	.read = dht11_read,
};
//dht11资源
static struct dht11_handle dht11_handle[DHT11_NUMBER];

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id dht11_of_match[] = {
	{.compatible = "atk,dht11"},
	{ /* Sentinel */ }
};
//平台驱动
static struct platform_driver dht11_drv = {
	.driver = {
		.name = "dht11",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = dht11_of_match,
	},
	.probe = dht11_probe,
	.remove = dht11_remove,
};

static irqreturn_t dht11_handler(int irq, void *dev)
{
	uint32_t id;

	id = (uint32_t)dev;

	if(!dht11_handle[id].irq_enable)
		return IRQ_HANDLED;

	//校验数据格式
	if(dht11_handle[id].edge_count % 2 == 0)
	{
		if(gpio_get_value(dht11_handle[id].gpio) != 1)
		{
			dht11_handle[id].transfer_result = 2;
			wake_up_interruptible(&dht11_handle[id].wait_queue);
			return IRQ_HANDLED;
		}
	}
	else
	{
		if(gpio_get_value(dht11_handle[id].gpio) != 0)
		{
			dht11_handle[id].transfer_result = 2;
			wake_up_interruptible(&dht11_handle[id].wait_queue);
			return IRQ_HANDLED;
		}
	}

	//记录脉冲边沿触发时间
	dht11_handle[id].edge_time[dht11_handle[id].edge_count] = ktime_get_real_ns();
	//脉冲边沿计数
	dht11_handle[id].edge_count++;
	//1bit响应+8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和，共计82个边沿
	if(dht11_handle[id].edge_count >= 82)
	{
		dht11_handle[id].transfer_result = 1;
		wake_up_interruptible(&dht11_handle[id].wait_queue);
	}

	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

static int dht11_start(struct dht11_handle *dht11)
{
	int32_t timeout;
	unsigned long irq_state;

	//GPIO设置为输出，并输出高电平，确保总线空闲
	gpio_direction_output(dht11->gpio, 1);
	udelay(30);

	/* 开始信号是一个低脉冲 + 一个高脉冲，低脉冲至少持续18ms，高脉冲持续20-40us */
	//输出一个18ms~30ms的低脉冲
	gpio_set_value(dht11->gpio, 0);
	mdelay(18);
	//关闭本核中断，目的是为了得到精确的30us延时
	local_irq_save(irq_state);
	//输出20us~40us的高脉冲
	gpio_set_value(dht11->gpio, 1);
	udelay(30);
	//主机将对应的GPIO管脚配置为输入，准备接收DHT11传来的数据
	gpio_direction_input(dht11->gpio);
	//恢复本核中断
	local_irq_restore(irq_state);

	//等待总线被拉低（等待响应信号开始）
	for(timeout=200; gpio_get_value(dht11->gpio) && timeout; timeout--)
	{
		udelay(1);
	}
	if(timeout <= 0)
		return -EAGAIN;

	return 0;
}

static int dht11_parse(struct dht11_handle *dht11, uint8_t *data)
{
	int32_t i, j, k;

	memset(data, 0, 5);
	for(i=0,k=2; i<5; i++)
	{
		for(j=0; j<8; j++)
		{
			/* 数据为0的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us，高脉冲持续26～28us */
			/* 数据为1的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us，高脉冲持续70us */
			//高脉冲大于35us认为是1
			if(dht11->edge_time[k+1]-dht11->edge_time[k] > 35000)
				data[i] |= 0x01 << (7 - j);
			k += 2;
		}
	}

	//和校验
	if(data[4] == data[0] + data[1] + data[2] + data[3])
		return 0;

	return -EINVAL;
}

static int dht11_poll(struct dht11_handle *dht11, uint8_t *data)
{
	int32_t i, j;
	int32_t timeout;

	//响应信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续80us，高脉冲持续80us
	for(timeout=200; !gpio_get_value(dht11->gpio) && timeout; timeout--)
	{
		udelay(1);
	}
	if(timeout <= 0)
		return -EAGAIN;
	for(timeout=200; gpio_get_value(dht11->gpio) && timeout; timeout--)
	{
		udelay(1);
	}
	if(timeout <= 0)
		return -EAGAIN;

	memset(data, 0, 5);
	for(i=0; i<5; i++)
	{
		for(j=0; j<8; j++)
		{
			/* 数据为0的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us，高脉冲持续26～28us */
			/* 数据为1的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us，高脉冲持续70us */
			//等待低电平结束
			for(timeout=200; !gpio_get_value(dht11->gpio) && timeout; timeout--)
			{
				udelay(1);
			}
			if(timeout <= 0)
				return -EAGAIN;
			//35us后依旧为高则是1
			udelay(35);
			if(gpio_get_value(dht11->gpio))
				data[i] |= 0x01 << (7 - j);
			//等待高电平结束
			for(timeout=200; gpio_get_value(dht11->gpio) && timeout; timeout--)
			{
				udelay(1);
			}
			if(timeout <= 0)
				return -EAGAIN;
		}
	}

	//和校验
	if(data[4] == data[0] + data[1] + data[2] + data[3])
		return 0;

	return -EINVAL;
}

static ssize_t dht11_read(struct file *file, char __user *buf, size_t len, loff_t *pos)
{
	uint32_t id;
	long result;
	unsigned long irq_state;
	struct dht11_data dht11_data;
	uint8_t data[5];

	id = MINOR(file->f_inode->i_rdev);
	if((id > DHT11_NUMBER) || (len < sizeof(struct dht11_data)))
		return -EINVAL;


	if((dht11_handle[id].irq > 0) &&
		(dht11_handle[id].irq_flags == (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)))
	{
		//使用中断
		//复位脉冲边沿时间缓存
		memset(dht11_handle[id].edge_time, 0, sizeof(dht11_handle[id].edge_time));
		dht11_handle[id].edge_count = 0;
		//产生开始信号
		result = dht11_start(&dht11_handle[id]);
		if(result < 0)
			return result;
		//启动中断处理
		dht11_handle[id].irq_enable = 1;
		//等待传输结束
		dht11_handle[id].transfer_result = 0;
		result = wait_event_interruptible_timeout(dht11_handle[id].wait_queue, dht11_handle[id].transfer_result, msecs_to_jiffies(1000));
		//停止中断处理
		dht11_handle[id].irq_enable = 0;
		//检查传输结果
		if(result == 0)
			return -ETIMEDOUT;
		if(result < 0)
			return -ERESTARTSYS;
		if(dht11_handle[id].transfer_result == 2)
			return -EAGAIN;
		//解析数据
		result = dht11_parse(&dht11_handle[id], data);
		if(result < 0)
			return result;
	}
	else
	{
		//使用轮询
		//产生开始信号
		result = dht11_start(&dht11_handle[id]);
		if(result == 0)
		{
			//关闭本核中断
			local_irq_save(irq_state);
			//轮询数据
			result = dht11_poll(&dht11_handle[id], data);
			//恢复本核中断
			local_irq_restore(irq_state);
		}
		if(result < 0)
			return result;
	}

	dht11_data.rh_integer = data[0];
	dht11_data.rh_decimal = data[1];
	dht11_data.t_integer = data[2];
	dht11_data.t_decimal = data[3];
	if(copy_to_user(buf, &dht11_data, sizeof(struct dht11_data)))
		return -EFAULT;

	return sizeof(struct dht11_data);
}

//设备和驱动匹配成功执行
static int dht11_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;
	struct device *device;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(pdev->dev.of_node, "id", &id);
	if(result != 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > DHT11_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}

	//检查是否占用
	if(dht11_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}
	pdev->id = id;

	//标记为已占用
	dht11_handle[id].use_flag = 1;
	//暂时不执行中断处理
	dht11_handle[id].irq_enable = 0;

	//初始化等待队列
	init_waitqueue_head(&dht11_handle[id].wait_queue);

	//获取GPIO号
	dht11_handle[id].gpio = of_get_named_gpio(pdev->dev.of_node, "data_pin", 0);
	if(dht11_handle[id].gpio < 0)
	{
		dht11_handle[id].use_flag = 0;
		printk("get gpio failed\r\n");
		return dht11_handle[id].gpio;
	}
	//申请GPIO
	result = gpio_request(dht11_handle[id].gpio, "dht11");
	if(result != 0)
	{
		dht11_handle[id].use_flag = 0;
		printk("request gpio failed\r\n");
		return result;
	}

	//获取中断号
	dht11_handle[id].irq = of_irq_get(pdev->dev.of_node, 0);
	if(dht11_handle[id].irq > 0)
	{
		//获取中断触发方式
		dht11_handle[id].irq_flags = irq_get_trigger_type(dht11_handle[id].irq);
		if(dht11_handle[id].irq_flags == (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING))
		{
			//注册中断处理函数
			result = request_irq(dht11_handle[id].irq, dht11_handler, dht11_handle[id].irq_flags, "dht11_irq", (void*)id);
			if(result < 0)
			{
				gpio_free(dht11_handle[id].gpio);
				dht11_handle[id].use_flag = 0;
				printk("irq request failed");
				return result;
			}
		}
	}

	//创建设备文件，将ID作为此设备的次设备号
	device = device_create(dht11_class, NULL, dht11_num+id, NULL, "dht11-%d", id);
	if(IS_ERR(device))
	{
		free_irq(dht11_handle[id].irq, (void*)id);
		gpio_free(dht11_handle[id].gpio);
		dht11_handle[id].use_flag = 0;
		printk("device create failed");
		return PTR_ERR(device);
	}

	return 0;
}

//设备或驱动卸载时执行
static int dht11_remove(struct platform_device *pdev)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = pdev->id;
	if(!dht11_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	device_destroy(dht11_class, dht11_num+id);
	if((dht11_handle[id].irq > 0) &&
		(dht11_handle[id].irq_flags == (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)))
		free_irq(dht11_handle[id].irq, (void*)id);
	gpio_free(dht11_handle[id].gpio);

	dht11_handle[id].use_flag = 0;

	return 0;
}

static int __init dht11_drv_init(void)
{
	int i;
	int err = 0;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<DHT11_NUMBER; i++)
	{
		dht11_handle[i].use_flag = 0;
		memset(dht11_handle[i].edge_time, 0, sizeof(dht11_handle[i].edge_time));
		dht11_handle[i].edge_count = 0;
		dht11_handle[i].irq_enable = 0;
	}

	//根据次设备号起始值动态注册字符设备号
	err = alloc_chrdev_region(&dht11_num, 0, DHT11_NUMBER, "atk,dht11");
	if(err != 0)
	{
		printk("alloc chrdev failed\r\n");
		return err;
	}
	printk("first device major %d, minor %d\r\n", MAJOR(dht11_num), MINOR(dht11_num));

	//初始化CDEV对象
	cdev_init(&dht11_cdev, &dht11_ops);
	//向系统添加CDEV对象
	err = cdev_add(&dht11_cdev, dht11_num, DHT11_NUMBER);
	if(err != 0)
	{
		unregister_chrdev_region(dht11_num, DHT11_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}

	//创建class对象
	dht11_class = class_create(THIS_MODULE, "dht11,class");
	if(IS_ERR(dht11_class))
	{
		cdev_del(&dht11_cdev);
		unregister_chrdev_region(dht11_num, DHT11_NUMBER);
		printk("class create failed");
		return PTR_ERR(dht11_class);
	}

	//注册平台驱动
	err = platform_driver_register(&dht11_drv);
	if(err != 0)
	{
		class_destroy(dht11_class);
		cdev_del(&dht11_cdev);
		unregister_chrdev_region(dht11_num, DHT11_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}
	return err;
}

static void __exit dht11_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&dht11_drv);
	//销毁class对象
	class_destroy(dht11_class);
	//从系统删除CDEV对象
	cdev_del(&dht11_cdev);
	//注销字符设备号
	unregister_chrdev_region(dht11_num, DHT11_NUMBER);
}

module_init(dht11_drv_init);
module_exit(dht11_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("dht11_dev");
